package com.api.syh56.shengyunhui.service.impl;

import com.api.syh56.shengyunhui.common.BaseUserInfo;
import com.api.syh56.shengyunhui.common.Constants;
import com.api.syh56.shengyunhui.common.UserInfoEnu;
import com.api.syh56.shengyunhui.controller.QuoteController;
import com.api.syh56.shengyunhui.entity.PayInfo;
import com.api.syh56.shengyunhui.entity.Quote;
import com.api.syh56.shengyunhui.entity.User;
import com.api.syh56.shengyunhui.entity.Waybill;
import com.api.syh56.shengyunhui.exception.BaseException;
import com.api.syh56.shengyunhui.properties.WechatProperties;
import com.api.syh56.shengyunhui.service.*;
import com.api.syh56.shengyunhui.util.CodeToOidUtil;
import com.api.syh56.shengyunhui.util.CommonUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Slf4j
public class WechatPayServiceImpl implements WechatPayService {

    @Autowired
    private WayBillService wayBillService;

    @Autowired
    private UserService userService;

    @Autowired
    private QuoteService quoteService;

    @Autowired
    private PayInfoService payInfoService;

    @Autowired
    private JsapiServiceExtension jsapiServiceExtension;

    @Autowired
    private AppServiceExtension appServiceExtension;

    @Autowired
    private TransferBatchService transferBatchService;

    @Autowired
    private RefundService refundService;

    @Autowired
    private CodeToOidUtil codeToOidUtil;

    @Autowired
    private WechatProperties wechatProperties;

    public Map<String,String> jsapiAndAppPrepay(String code, Long waybillId, Long quoteId, String priceType, String platform)  {


        Long uid = Long.valueOf(BaseUserInfo.get(UserInfoEnu.id.getCode()));
        User user = userService.getById(uid);

        Waybill waybill = wayBillService.getById(waybillId);

        Quote quote = quoteService.getById(quoteId);
        Long driverId = quote.getDriverId();

        short waybillStatus = waybill.getWaybillStatus();
        /**
         * 支付方式 到付 现付 月结
         */
        short payMethod = waybill.getPayMethod();
//        log.info(String.valueOf(waybillStatus));

        // 现付  满足该条件
        if(!Constants.WaybillStatus.AWAIT_QUOTE.equals(waybillStatus) && !Constants.WaybillStatus.AWAIT_SETTLEMENT.equals(waybillStatus) ){
//        if(!Constants.WaybillStatus.IN_PAY.equals(waybillStatus) ){
            throw  new BaseException("运单状态不满足要求，无法支付定金或运费");
        }

        //判断是否为运单货主本人
        if(!uid.equals(waybill.getShiperId())){
            throw  new BaseException("非运单货主本人操作");
        }


        // 微信支付API所需参数
        BigDecimal tmp_price = BigDecimal.valueOf(0);
        String payDescription = "";//描述
        Short amountType = 0;//金额类型
        String orderNum = "";
        Boolean isSupportFapiao = false;


        // 到付 月结
        if (Constants.PayMethod.PAY_LATER.equals(payMethod) || Constants.PayMethod.MONTHLY_PAYMENT.equals(payMethod)){
            if ("deposit".equals(priceType)){
                //确认报价时以quote定金为准
                tmp_price = quote.getDeposit();
                payDescription = waybill.getWaybillNumber()+" 定金";
                amountType = Constants.AmountType.DEPOSIT;
                isSupportFapiao = false;
                orderNum = waybill.getWaybillNumber();
            }else {
                //结算时以waybill.getOfferAll = 运费OfferEnd + 5%平台服务费OfferInit
//                tmp_price = waybill.getOfferAll();
                tmp_price = waybill.getActAmount();
                payDescription = waybill.getWaybillNumber()+" 运费";
                amountType = Constants.AmountType.SHIPFEE;
                isSupportFapiao = true;
                orderNum = waybill.getWaybillNumber();
            }
        }
        // 现付
        else if (Constants.PayMethod.PAY_NOW.equals(payMethod)){
            Quote quoteDB = quoteService.getById(quoteId);
//            tmp_price = quoteDB.getOfferAll();
            tmp_price = quoteDB.getActAmount();
            payDescription = waybill.getWaybillNumber()+" 运费";
            amountType = Constants.AmountType.SHIPFEE;
            isSupportFapiao = true;
            orderNum = waybill.getWaybillNumber();
        }



        //支付金额(以分为单位)（定金 金额）
        int price  =  tmp_price.multiply(new BigDecimal("100")).intValue();
        // 商户系统支付订单号(运单编号) = 运单号+3位随机数
        orderNum += CommonUtil.getRandomString(3,"0123456789");


        Map<String, String> data = new HashMap<>();
        if ("mini".equals(platform)){
            // request.setXxx(val)设置所需参数，具体参数可见Request定义
            PrepayRequest jsapirequest = new PrepayRequest();

            Payer payer = new Payer();

            Map<String, String> stringStringMap = codeToOidUtil.getOpenIdByCode(code);
            String openid = stringStringMap.get("openid");
            System.out.println("openid");
            System.out.println(openid);
            //微信用户openid
            payer.setOpenid(openid);

            Amount amount = new Amount();
            amount.setTotal(price);
            amount.setCurrency("CNY");
            jsapirequest.setAmount(amount);
            jsapirequest.setAppid(wechatProperties.getAppid());
            jsapirequest.setMchid(wechatProperties.getMerchantId());
            //支付描述
            jsapirequest.setDescription(payDescription);
            //支付通知消息回调
            jsapirequest.setNotifyUrl(wechatProperties.getNotifyUrl());//回调地址
            //是否支持开发票
            jsapirequest.setSupportFapiao(isSupportFapiao);
            //支付超时时间设为30分钟
            ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).plusMinutes(30);
            // 格式化为RFC 3339格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
            String formattedDateTime = zonedDateTime.format(formatter);
            jsapirequest.setTimeExpire(formattedDateTime);


            //商户系统支付订单号(运单编号)
            log.info("订单号:{}", orderNum);
            jsapirequest.setOutTradeNo(orderNum);
            //付款人
            jsapirequest.setPayer(payer);
            //附加信息（运单id 金额类型）
            Map<String, Object> additionalInfo = new HashMap<>();
            additionalInfo.put("waybillId", waybillId.toString());
            additionalInfo.put("priceType", priceType);
            additionalInfo.put("quoteId", quote.getId().toString());
//            additionalInfo.put("quoteOfferPrice",quote.getOfferPrice());
//            additionalInfo.put("payMethod", payMethod);
            System.out.println(additionalInfo);


            // 将Map转换为JSON字符串
            String json = new Gson().toJson(additionalInfo);
            jsapirequest.setAttach(json);
            System.out.println(jsapirequest);
            // response包含了调起支付所需的所有参数，可直接用于前端调起支付
            PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = jsapiServiceExtension.prepayWithRequestPayment(jsapirequest);

            System.out.println(prepayWithRequestPaymentResponse);
            data.put("appid",prepayWithRequestPaymentResponse.getAppId());//appid
            data.put("timeStamp",prepayWithRequestPaymentResponse.getTimeStamp());
            data.put("nonceStr",prepayWithRequestPaymentResponse.getNonceStr());
            data.put("package",prepayWithRequestPaymentResponse.getPackageVal());
            data.put("signType",prepayWithRequestPaymentResponse.getSignType());//签名方式
            data.put("paySign",prepayWithRequestPaymentResponse.getPaySign());
            System.out.println(prepayWithRequestPaymentResponse);
        }
        else if ("app".equals(platform)) {

            //打印String code, Long waybillId, Long quoteId, String priceType, String platform
            System.out.println("code"+code);
            System.out.println("waybillId"+waybillId);
            System.out.println("quoteId"+quoteId);
            System.out.println("priceType"+priceType);
            System.out.println("platform"+platform);

            // request.setXxx(val)设置所需参数，具体参数可见Request定义
            com.wechat.pay.java.service.payments.app.model.PrepayRequest AppprepayRequest = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();


            com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
            amount.setTotal(price);
            amount.setCurrency("CNY");
            AppprepayRequest.setAmount(amount);
            AppprepayRequest.setAppid(wechatProperties.getAPP_appid());
            AppprepayRequest.setMchid(wechatProperties.getMerchantId());
            //支付描述
            AppprepayRequest.setDescription(payDescription);
            //支付通知消息回调
            AppprepayRequest.setNotifyUrl(wechatProperties.getNotifyUrl());//回调地址
            //是否支持开发票
            AppprepayRequest.setSupportFapiao(isSupportFapiao);
            //支付超时时间设为30分钟
            ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).plusMinutes(30);
            // 格式化为RFC 3339格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
            String formattedDateTime = zonedDateTime.format(formatter);
            AppprepayRequest.setTimeExpire(formattedDateTime);


            //商户系统支付订单号(运单编号)
            log.info("订单号:{}", orderNum);
            AppprepayRequest.setOutTradeNo(orderNum);
            //付款人

//            AppprepayRequest.setPayer(payer);
            //附加信息（运单id 金额类型）
            Map<String, Object> additionalInfo = new HashMap<>();
            additionalInfo.put("waybillId", waybillId.toString());
            additionalInfo.put("priceType", priceType);
            additionalInfo.put("quoteId", quote.getId().toString());
//            additionalInfo.put("quoteOfferPrice",quote.getOfferPrice());
//            additionalInfo.put("payMethod", payMethod);
            System.out.println(additionalInfo);


            // 将Map转换为JSON字符串
            String json = new Gson().toJson(additionalInfo);
            AppprepayRequest.setAttach(json);
            com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse AppprepayWithRequestPaymentResponse = appServiceExtension.prepayWithRequestPayment(AppprepayRequest);
            System.out.println(AppprepayWithRequestPaymentResponse);
            data.put("appid",AppprepayWithRequestPaymentResponse.getAppid());//appid
            data.put("partnerid",AppprepayWithRequestPaymentResponse.getPartnerId());//商户号mchid对应的值
            data.put("prepayid",AppprepayWithRequestPaymentResponse.getPrepayId());
            data.put("package",AppprepayWithRequestPaymentResponse.getPackageVal());
            data.put("noncestr",AppprepayWithRequestPaymentResponse.getNonceStr());
            data.put("timestamp",AppprepayWithRequestPaymentResponse.getTimestamp());
            data.put("sign",AppprepayWithRequestPaymentResponse.getSign());//签名

        }


        PayInfo payInfo = new PayInfo().builder()
                .waybillId(waybillId)
                .PayNum(orderNum)
                .payer(uid)
                .payee(driverId)
                .amount(tmp_price)
                .amountType(amountType)
                .state(Constants.PaymentStatus.UN_PAID)
                .description(platform)//app or mini
                .build();
        payInfoService.save(payInfo);

        return data;
    }

    public void wxpayrefund(Long waybillId,Short role){

        Waybill waybill = wayBillService.getById(waybillId);

        //如果操作人不是管理员，需要验证是否运单已结算，才可退回定金
        //如果是管理员，可以在定金支付后主动取消运单，并返还定金
        if (!Constants.Role.SUPERADMIN.equals(role)){
            if (waybill.getWaybillStatus()!= Constants.WaybillStatus.SETTLED && waybill.getDeliveryStatus() != Constants.DeliveryStatus.SETTLED){
                throw new BaseException("运单未结算");
            }
        }
        if (Constants.WaybillStatus.SETTLED.equals(waybill.getWaybillStatus())) {
            throw new BaseException("运单已被结算,无法退款");
        }
        QueryWrapper<PayInfo> payInfoQueryWrapper = new QueryWrapper<>();
//        payInfoQueryWrapper.lambda()
//                .eq(PayInfo::getWaybillId, waybillId)
//                .eq(PayInfo::getAmountType, Constants.AmountType.DEPOSIT)
//                .eq(PayInfo::getState, Constants.PaymentStatus.PAID);
        if (Constants.PayMethod.PAY_NOW.equals(waybill.getPayMethod())) {
            payInfoQueryWrapper.lambda().eq(PayInfo::getAmountType,Constants.AmountType.SHIPFEE);
        }else{
            payInfoQueryWrapper.lambda().eq(PayInfo::getAmountType,Constants.AmountType.DEPOSIT);
        }
        payInfoQueryWrapper.lambda()
                .eq(PayInfo::getWaybillId, waybillId)
//                .eq(PayInfo::getAmountType, Constants.AmountType.DEPOSIT)
                .eq(PayInfo::getState, Constants.PaymentStatus.PAID);
        List<PayInfo> payInfoList = payInfoService.list(payInfoQueryWrapper);

        if (payInfoList.size() == 0) {
            throw new BaseException("运单未支付定金或定金已退");
        } else if (payInfoList.size() != 1) {
            throw new BaseException("运单对应定金支付信息异常");
        }
        PayInfo payInfo = payInfoList.get(0);

        Long uid = Long.valueOf(BaseUserInfo.get("id"));



        BigDecimal payInfoAmount = payInfo.getAmount();
        Long payInfoAmountLONG = payInfoAmount.multiply(new BigDecimal("100")).longValue();
        try {
            CreateRequest request = new CreateRequest();


            AmountReq amount = new AmountReq();
            amount.setRefund(payInfoAmountLONG);
            amount.setTotal(payInfoAmountLONG);
            amount.setCurrency("CNY");
            request.setAmount(amount);

            request.setNotifyUrl(wechatProperties.getRefundNotifyUrl());
            request.setOutTradeNo(payInfo.getPayNum());
            //3位随机数
            String characters = "0123456789abcdefghijklmnopqrstuvwxyz";
            Random random = new Random();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 3; i++) {
                int index = random.nextInt(characters.length());
                sb.append(characters.charAt(index));
            }
            String randomNumeric = sb.toString();

            String OutRefundNo = payInfo.getPayNum() + randomNumeric;
            request.setOutRefundNo(OutRefundNo);
//            request.setReason();
            Refund response = refundService.create(request);

            //更新pay_info表
            payInfo.setOutRefundNo(OutRefundNo);
            payInfoService.saveOrUpdate(payInfo);
        } catch (HttpException e) { // 发送HTTP请求失败
            // 调用e.getHttpRequest()获取请求打印日志或上报监控，更多方法见HttpException定义
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            // 调用e.getResponseBody()获取返回体打印日志或上报监控，更多方法见ServiceException定义
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            // 调用e.getMessage()获取信息打印日志或上报监控，更多方法见MalformedMessageException定义
        }
    }

    void transferBatch(){


        InitiateBatchTransferRequest initiateBatchTransferRequest = new InitiateBatchTransferRequest();
//        initiateBatchTransferRequest.setAppid();
//        initiateBatchTransferRequest.setBatchName();
//        initiateBatchTransferRequest.setTotalNum(1);
//        initiateBatchTransferRequest.setTotalAmount(1L);
//
//        TransferDetailInput transferDetailInput = new TransferDetailInput();
//        transferDetailInput.setOpenid();
//
//        initiateBatchTransferRequest.setTransferDetailList();
//        InitiateBatchTransferResponse initiateBatchTransferResponse = transferBatchService.initiateBatchTransfer();



    }
}
